﻿// Imports
using System.Text.RegularExpressions;

namespace Nickel
{

    /// <summary>
    /// Markup parser
    /// </summary>
    public class Markup
    {

        /// <summary>
        /// Flag to toggle image layout
        /// </summary>
        public static bool bAlignRight = true;

        /// <summary>
        /// Finds first image in input string and formats img tag
        /// </summary>
        /// <param name="input">Marked up text</param>
        /// <returns>img tag if found or empty string</returns>
        public static string FindImage(string input)
        {

            // Declare return string
            string output = string.Empty;

            // Find tags
            foreach (Match match in ValidMarkup.Matches(input))
            {

                // Declare URL
                string strUrl = string.Empty;

                // Remove brackets
                string strMatch = match.Value.Replace("[", "");
                strMatch = strMatch.Replace("]", "");

                // Split tag to array
                string[] arrMatch = strMatch.Split(" ".ToCharArray());
                string tag = arrMatch[0].Trim();

                // Get URL
                if (arrMatch.Length > 1) 
                    strUrl = new Regex("\"|url=", RegexOptions.IgnoreCase).Replace(arrMatch[1], "");

                // This is an image
                if (tag == Constants.MARKUP_FILE && StringHelper.ValidFile(FilePatternType.IMAGE).IsMatch(strUrl))
                {

                    // Write image tag
                    output += "<img src=\"" + strUrl + "\" align=\"" + (bAlignRight ? "right" : "left") + "\" hspace=\"10\" vspace=\"10\" />";

                    // Break loop
                    break;

                }

            }

            // Return output
            return output;

        }

        /// <summary>
        /// Base URL
        /// </summary>
        public static string strBaseUrl;

        /// <summary>
        /// Closing tag for file
        /// </summary>
        private static string strCloseFileTag;

        /// <summary>
        /// Turns line breaks into list items
        /// </summary>
        /// <param name="match">Match from Regex</param>
        /// <returns>Modified string</returns>
        private static string ListItems(Match match)
        {

            // DO IT!
            return match.Value.Replace("<br />", "</li><li>");

        }

        /// <summary>
        /// Parses markup into HTML
        /// </summary>
        /// <param name="input">Input string with markup</param>
        /// <returns>String as HTML</returns>
        public static string Parse(string input)
        {

            // No real HTML allowed
            input = input.Replace("<", "&lt;");
            input = input.Replace(">", "&gt;");

            // Parse markup
            string output = ValidMarkup.Replace(input, new MatchEvaluator(Parse));

            // Replace line breaks
            output = new Regex(@"\n|\r|\n\r", RegexOptions.IgnoreCase).Replace(output, "<br />");

            // Builds lists
            output = new Regex(@"<ul\b[^>]*>(.*?)</ul>", RegexOptions.IgnoreCase).Replace(output, new MatchEvaluator(ListItems));

            // Convert line breaks to HTML and return output
            return output;

        }

        /// <summary>
        /// Parses markup into HTML
        /// </summary>
        /// <param name="input">Input string with markup</param>
        /// <returns>String as HTML</returns>
        public static string ParseLite(string input)
        {

            // No real HTML allowed
            input = input.Replace("<", "&lt;");
            input = input.Replace(">", "&gt;");

            // Parse markup
            string output = ValidMarkup.Replace(input, new MatchEvaluator(ParseLite));

            // Replace line breaks
            output = new Regex(@"\n|\r|\n\r", RegexOptions.IgnoreCase).Replace(output, "<br />");

            // Builds lists
            output = new Regex(@"<ul\b[^>]*>(.*?)</ul>", RegexOptions.IgnoreCase).Replace(output, new MatchEvaluator(ListItems));

            // Convert line breaks to HTML and return output
            return output;

        }

        /// <summary>
        /// Parses markup into HTML
        /// </summary>
        /// <param name="match">Match from Regex</param>
        /// <returns>Modified string</returns>
        private static string Parse(Match match)
        {

            // Declare output string
            string output = string.Empty;

            // Remove brackets
            string strMatch = match.Value.Replace("[", "");
            strMatch = strMatch.Replace("]", "");

            // Split tag to array
            string[] arrMatch = strMatch.Split(" ".ToCharArray());
            string tag = arrMatch[0].Trim();

            // Check tag length
            if (tag.Length > 0)
            {

                // Flag is true if this is a closing tag
                bool bClosing = tag.Substring(0, 1) == "/";
                if (bClosing) 
                    tag = tag.Substring(1, tag.Length - 1);

                // URL for links and files
                string strUrl = string.Empty;

                // Key on tag
                switch (tag)
                {

                    case Constants.MARKUP_BOLD:

                        // Build tag
                        output += bClosing ? "</strong>" : "<strong>";

                        break;
                    case Constants.MARKUP_CODE:

                        // Build tag
                        output += bClosing ? "</pre>" : "<pre>";

                        break;
                    case Constants.MARKUP_FILE:

                        // Closing
                        if (bClosing)
                        {

                            // Close tag
                            output += strCloseFileTag;

                        }
                        else
                        {

                            // Get URL
                            if (arrMatch.Length > 1) 
                                strUrl = new Regex("\"|url=", RegexOptions.IgnoreCase).Replace(arrMatch[1], "");

                            // Find embed type
                            if (StringHelper.ValidFile(FilePatternType.ATTACHMENT).IsMatch(strUrl))
                            {

                                // Write attachment tag
                                output += "<div class=\"attachment\"><a target=\"_blank\" href=\"" +
                                    strUrl + "\"><img src=\"" + strBaseUrl + "images/attachment.png\" /> ";

                                // Set closing tag
                                strCloseFileTag = "</a></div>";

                            }
                            else if (StringHelper.ValidFile(FilePatternType.IMAGE).IsMatch(strUrl))
                            {

                                // Write image tag
                                output += "<img src=\"" + strUrl + "\" align=\"" + (bAlignRight ? "right" : "left") + "\" hspace=\"10\" vspace=\"10\" />";

                                // Set closing tag
                                strCloseFileTag = "";

                                // Toggle alignment
                                bAlignRight = !bAlignRight;

                            }
                            else if (StringHelper.ValidFile(FilePatternType.MEDIA).IsMatch(strUrl))
                            {

                                // Start embed
                                output += "<div class=\"embed\">";

                                // Get extensions
                                string strExtension = strUrl.ToLower().Substring(strUrl.LastIndexOf(".") + 1);

                                // This is audio
                                if (strExtension == "aif" ||
                                    strExtension == "aiff" ||
                                    strExtension == "mp3" ||
                                    strExtension == "ogg" ||
                                    strExtension == "wav")
                                {

                                    // Embed audio
                                    output += "<audio style=\"width:480px;\" src=\"" + strUrl + "\" controls>Your browser does not support the &quot;audio&quot; element.</audio><br />";

                                }
                                else if (strExtension == "swf")
                                {

                                    // Embed SWF
                                    output += "<embed width=\"480\" height=\"360\" type=\"application/x-shockwave-flash\" src=\"" + strUrl + "\" pluginspage=\"http://www.adobe.com/go/getflashplayer\" />";

                                }
                                else
                                {

                                    // Embed video
                                    output += "<video height=\"360\" width=\"480\" controls src=\"" + strUrl + "\">Your browser does not support the &quot;video&quot; element.</video><br />";

                                }

                                // Set closing tag
                                strCloseFileTag = "</div>";

                            }
                            else if (StringHelper.ValidVimeo.IsMatch(strUrl))
                            {

                                // Find ID
                                Match matchId = StringHelper.ValidVimeo.Match(strUrl);
                                if (matchId != null)
                                {

                                    // Add video
                                    output += "<div class=\"embed\"><iframe src=\"http://player.vimeo.com/video/" +
                                        matchId.Groups[1].Value + "\" width=\"600\" height=\"400\" " +
                                        "frameborder=\"0\"></iframe><br />";

                                    // Set closing tag
                                    strCloseFileTag = "</div>";

                                }
                                else
                                {

                                    // Set closing tag
                                    strCloseFileTag = "";

                                }


                            }
                            else if (StringHelper.ValidYouTube.IsMatch(strUrl))
                            {

                                // Find ID
                                Match matchId = StringHelper.ValidYouTube.Match(strUrl);
                                if (matchId != null)
                                {

                                    // Clean up ID
                                    string strId = matchId.Groups[1].Value;

                                    // Add video
                                    output += "<div class=\"embed\"><iframe src=\"http://www.youtube.com/embed/" +
                                        matchId.Groups[1].Value + "\" width=\"600\" height=\"400\" " +
                                        "frameborder=\"0\"></iframe><br />";

                                    // Set closing tag
                                    strCloseFileTag = "</div>";

                                }
                                else
                                {

                                    // Set closing tag
                                    strCloseFileTag = "";

                                }

                            }

                        }

                        break;
                    case Constants.MARKUP_ITALIC:

                        // Build tag
                        output += bClosing ? "</em>" : "<em>";

                        break;
                    case Constants.MARKUP_LINK:

                        // Start tag
                        if (!bClosing) 
                            output += "<a target=\"_blank\" href=\"";

                        // Add URL
                        if (arrMatch.Length > 1 && !bClosing) 
                            output += new Regex("\"|url=", RegexOptions.IgnoreCase).Replace(arrMatch[1], "");

                        // Finish tag
                        output += bClosing ? "</a>" : "\">";

                        break;
                    case Constants.MARKUP_LIST:

                        // Build tag
                        output += bClosing ? "</li></ul>" : "<ul><li>";

                        break;
                    case Constants.MARKUP_UNDERLINE:

                        // Build tag
                        output += bClosing ? "</u>" : "<u>";

                        break;
                    default:

                        // Just pass value otherwise
                        output += match.Value;

                        break;

                }

            }
            else
            {

                // Just pass value otherwise
                output = match.Value;

            }

            // Return outout
            return output;

        }

        /// <summary>
        /// Parses markup into HTML
        /// </summary>
        /// <param name="match">Match from Regex</param>
        /// <returns>Modified string</returns>
        private static string ParseLite(Match match)
        {

            // Declare output string
            string output = string.Empty;

            // Remove brackets
            string strMatch = match.Value.Replace("[", "");
            strMatch = strMatch.Replace("]", "");

            // Split tag to array
            string[] arrMatch = strMatch.Split(" ".ToCharArray());
            string tag = arrMatch[0].Trim();

            // Check tag length
            if (tag.Length > 0)
            {

                // Flag is true if this is a closing tag
                bool bClosing = tag.Substring(0, 1) == "/";
                if (bClosing) 
                    tag = tag.Substring(1, tag.Length - 1);

                // URL for links and files
                string strUrl = string.Empty;

                // Key on tag
                switch (tag)
                {

                    case Constants.MARKUP_BOLD:

                        // Build tag
                        output += bClosing ? "</strong>" : "<strong>";

                        break;
                    case Constants.MARKUP_CODE:

                        // Build tag
                        output += bClosing ? "</pre>" : "<pre>";

                        break;
                    case Constants.MARKUP_ITALIC:

                        // Build tag
                        output += bClosing ? "</em>" : "<em>";

                        break;
                    case Constants.MARKUP_LINK:

                        // Start tag
                        if (!bClosing) 
                            output += "<a target=\"_blank\" href=\"";

                        // Add URL
                        if (arrMatch.Length > 1 && !bClosing) 
                            output += new Regex("\"|url=", RegexOptions.IgnoreCase).Replace(arrMatch[1], "");

                        // Finish tag
                        output += bClosing ? "</a>" : "\">";

                        break;
                    case Constants.MARKUP_LIST:
                        
                        // Build tag
                        output += bClosing ? "</li></ul>" : "<ul><li>";

                        break;
                    case Constants.MARKUP_UNDERLINE:

                        // Build tag
                        output += bClosing ? "</u>" : "<u>";

                        break;
                    default:

                        // Just pass value otherwise
                        output += match.Value;

                        break;

                }

            }
            else
            {

                // Just pass value otherwise
                output = match.Value;

            }

            // Return outout
            return output;

        }

        /// <summary>
        /// Validates and finds markup
        /// </summary>
        private static Regex ValidMarkup = new Regex(@"\[(.|\n)*?\]", RegexOptions.IgnoreCase);

    }

}
